/**
  ******************************************************************************
  * @author     Chris
  * @since      2024/6/12 10:36
  *
  * @file       pd_timer.c
  * @brief      Timer peripheral driver.
  *
  * @note       This file contains the peripheral driver for the Timer.
  *
  * @warning    None.
  ******************************************************************************
  * Change Logs:
  *   Date          Author       Notes
  *   2024/6/12     Chris        the first version
  *
  ******************************************************************************
  */

#include <stm32f4xx_ll_tim.h>
#include <stm32f4xx_ll_bus.h>
#include "pd_timer.h"

void Timer_init_(const Timer *this) {
    // RCC init
#if defined(TIM2)
    if (this->TIMx == TIM2) LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
#endif /* TIM2 */
#if defined(TIM3)
    if (this->TIMx == TIM3) LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);
#endif /* TIM3 */
#if defined(TIM4)
    if (this->TIMx == TIM4) LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM4);
#endif /* TIM4 */
#if defined(TIM5)
    if (this->TIMx == TIM5) LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM5);
#endif /* TIM5 */
#if defined(TIM6)
    if (this->TIMx == TIM6) LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM6);
#endif /* TIM6 */
#if defined(TIM7)
    if (this->TIMx == TIM7) LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM7);
#endif /* TIM7 */
#if defined(TIM12)
    if (this->TIMx == TIM12) LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM12);
#endif /* TIM12 */
#if defined(TIM13)
    if (this->TIMx == TIM13) LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM13);
#endif /* TIM13 */
#if defined(TIM14)
    if (this->TIMx == TIM14) LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM14);
#endif /* TIM14 */
#if defined(LPTIM1)
    if (this->TIMx == LPTIM1) LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LPTIM1);
#endif /* LPTIM1 */

    // Init the Timer Base Unit
    LL_TIM_InitTypeDef TIM_InitStruct = {0};
    TIM_InitStruct.Prescaler         = this->Prescaler;
    TIM_InitStruct.CounterMode       = this->CounterMode;
    TIM_InitStruct.Autoreload        = this->Autoreload;
    TIM_InitStruct.ClockDivision     = this->ClockDivision;
    TIM_InitStruct.RepetitionCounter = this->RepetitionCounter;
    LL_TIM_Init(this->TIMx, &TIM_InitStruct);
}

uint32_t Timer_getCounter_(const Timer *this) {
    return LL_TIM_GetCounter(this->TIMx);
}

void Timer_constructor(Timer *this, TIM_TypeDef *TIMx, uint16_t Prescaler, uint32_t Autoreload) {
    static struct TimerVtbl vtbl = {
        .init = &Timer_init_,
        .get_counter = &Timer_getCounter_,
    };

    this->vptr = &vtbl;

    this->TIMx              = TIMx;
    this->Prescaler         = Prescaler;
    this->Autoreload        = Autoreload;
    this->CounterMode       = LL_TIM_COUNTERMODE_UP;
    this->ClockDivision     = LL_TIM_CLOCKDIVISION_DIV1;
    this->RepetitionCounter = 0x00000000U;
}
